﻿<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

<title>DragonTimer</title>

<script type="text/javascript" language="javascript" src="js/system.js"></script>
<script type="text/javascript" language="javascript" src="js/transition.js"></script>
<script type="text/javascript" language="javascript" src="js/common.js"></script>
<script type="text/javascript" language="javascript" src="js/events.js"></script>

<style type="text/css">
@font-face
{
	font-family: 'Roboto Regular';
	font-style: normal;
	font-weight: normal;
	src: url('fonts/Roboto-Regular.ttf'), url('fonts/Roboto-Regular.eot');
}
body
{
    margin: 0px;
    width: 127px;
    height: 350px;
	font-family: arial;
	font-size: 10px;
	background-color: #000;
	color: #eee;
	overflow: hidden;
}
#event-template
{
	display: none;
}
#container
{
	width: 127px;
	position: relative;
	overflow: hidden;
}
#refresh
{
	font-size: 10px;
	color: #ccc;
	font-weight: normal;
	position: absolute;
	left: 2px;
	bottom: 2px;
	display: block;
	z-index: 5;
}
#refresh div.button
{
	width: 24px;
	height: 24px;
	background: url(images/refresh.png) no-repeat;
	cursor: pointer;
	display: inline-block;
	*display: inline;
    zoom: 1;

}
#refresh div.button:hover
{
	background: url(images/refresh-active.png) no-repeat;
}
#refresh-age
{
	position: relative;
	left: 3px;
	bottom: 1px;
}
div.timer
{
	 width: 127px;
	 height: 50px;
	 position: relative;
	 background-image: url(images/unknown.jpg);
	 background-repeat: no-repeat;
	 background-position: center;
	 cursor: pointer;
}
div.timer span[type='timer']
{
	font-family: 'Roboto Regular';
	font-size: 12px;
	font-weight: normal;
	text-align: right;
	position: absolute;
	bottom: 2px;
	right: 5px;
	filter: progid:DXImageTransform.Microsoft.Glow(color=000000,strength=1);
	z-index: 1;
	text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000;
}
div.timer.compact span[type='timer']
{
	font-size: 11px;
	bottom: 0px;
	filter: alpha(opacity=70), progid:DXImageTransform.Microsoft.Glow(color=000000,strength=1);
	opacity: 0.7;
	text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000;
}
div.timer span[type='timer'] span
{
	font-family: 'Roboto Regular';
	font-size: 9px;
	padding-left: 1px;
}
div.timer.compact span[type='timer'] span
{
	font-size: 9px;
}
div.timer div.daily-reset
{
	width: 20px;
	height: 20px;
	border: 0px;
	background: url(images/daily.png) no-repeat;
	position: absolute;
	bottom: 1px;
	left: 3px;
}
div.timer span[type='title']
{
	display: none;
	
	font-family: 'Roboto Regular';
	font-size: 10px;
	position: absolute;
	top: 0px;
	left: 1px;
	color: #fff;
	font-weight: normal;
	filter: alpha(opacity=70), progid:DXImageTransform.Microsoft.Glow(color=000000,strength=3);
	opacity: 0.7;
	z-index: 1;
	text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000;
}
div.timer span[type='icons']
{
	position: absolute;
	right: 5px;
	bottom: 18px;
	z-index: 1;
	text-align: right;
	overflow: hidden;
	height: 16px;
	width: 100px;
	filter: alpha(opacity=70);
	opacity: 0.7;
}
div.timer.compact span[type='icons']
{
	bottom: 10px;
	filter: alpha(opacity=40);
	opacity: 0.4;
}
div.timer span[type='icons'] img
{
	width: 16px;
	height: 16px;
	border: 1px;
}
div.timer.compact span[type='icons'] img
{
	width: 12px;
	height: 12px;
}
div.timer div.info
{
	position: absolute;
	right: 3px;
	top: 3px;
	z-index: 1;
	width: 12px;
	height: 12px;
	background: url(images/info.png) no-repeat;
	
	display: none;
}
div.timer div.info:hover
{
	background: url(images/info-hover.png) no-repeat;
}
div.timer div.info-button
{
	position: absolute;
	border: 1px solid #000;
	background-color: #fff;
	color: #000;
	font-size: 11px;
	font-family: 'Roboto Regular';
	left: 13px;
	right: 13px;
	top: 17px;
	text-align: center;
	padding-top: 2px;
	padding-bottom: 2px;
	display: none;
	z-index: 1;
}
div.timer div.info-button:hover
{
	background-color: #ccc;
}
div.timer div.close
{
	position: absolute;

	right: 3px;
	top: 3px;
	z-index: 1;
	width: 16px;
	height: 16px;
	background: url(images/event-close.png) no-repeat;
	cursor: pointer;
	
	display: none;
}
div.timer div.close:hover
{
	background: url(images/event-close-hover.png) no-repeat;
}
div.timer .unknown
{
	color: #999;
}
div.timer .inactive
{
	color: #999;
}
div.timer .invalid
{
	color: #ab9575;
}
div.timer .window-out
{
	color: #DACFC3;
}
div.timer .active
{
	color: #99FF33; /*#65dc20;*/
}
div.timer .extended
{
	color: #5CB800;
}
div.timer .blocking
{
	color: #d51d1d;
}
div.timer .waiting
{
	color: #D31D78;
}
div.timer .preevent
{
	color: #ff3;
}
div.timer .window
{
	color: #FEFEFE; /*#3399FF;*/
}
div.timer .darken
{
	position: absolute;
	top: 0px;
	left: 0px;
	background-color: #000;
	filter: alpha(opacity=50);
	opacity: 0.5;
	width: 100%;
	height: 100%;
	z-index: 0;
}
#selected-event
{
	position: relative;
	z-index: 1;
	width: 127px;
	left: -5px;
}
#event-menu.bottom #selected-event
{
	position: absolute;
	bottom: -50px;
}
#selected-event .timer
{
	width: 100%;
}
#event-menu
{
	position: absolute;
	left: 0px;
	top: 0px;
	width: 100%;
	height: 100%;
	z-index: 5;
	display: none;
}

#event-menu .background
{
	position: absolute;
	left: 0px;
	top: 0px;
	width: 100%;
	height: 100%;
	background-color: #000;
	z-index: 0;
	filter: alpha(opacity=65);
	opacity: 0.65;
}

#event-menu .arrow
{
	background: url(images/event-menu-arrow.png) no-repeat center;
	width: 117px;
	height: 5px;
	filter: alpha(opacity=95);
	opacity: 0.95;
	position: relative;
	top: -5px;
	z-index: 1;
}

#event-menu.bottom .arrow
{
	background: url(images/event-menu-arrow-bottom.png) no-repeat center;
	position: absolute;
	top: auto;
	bottom: -5px;
}

#event-menu .container
{
	position: absolute;
	z-index: 1;
	left: 5px;
}

#event-menu .content
{
	position: relative;
	top: -5px;
	width: 115px;
	height: 250px;
	text-align: center;
}
#event-menu.bottom .content
{
	top: 0px;
}
#event-menu .close
{
	position: absolute;
	right: 5px;
	top: 5px;
	width: 8px;
	height: 9px;
	background: url(images/close-gray.png) no-repeat;
	cursor: pointer;
	z-index: 1;
}
#event-menu .close:hover
{
	background: url(images/close.png) no-repeat;
}
#event-menu .close:active
{
	background: url(images/close-gray.png) no-repeat;
}
#event-menu .content .background
{
	position: absolute;
	left: 0px;
	top: 0px;
	width: 100%;
	height: 100%;
	z-index: 0;
	border-left: 1px solid #000;
	border-right: 1px solid #000;
	border-bottom: 1px solid #000;
	background-color: #fff;
	filter: alpha(opacity=95);
	opacity: 0.95;
}
#event-menu .content .icons
{
	width: 74px;
	position: absolute;
	top: 20px;
	left: 20px;
	z-index: 1;
}
#event-menu .content .icons img
{
	width: 32px;
	height: 32px;
	border: 0px;
	cursor: pointer;
	margin-bottom: 10px;
}
#event-menu .content .waypoint
{
	width: 40px;
	height: 40px;
	position: absolute;
	bottom: 5px;
	left: 37px;
	z-index: 1;
	background: url(images/waypoint.png) no-repeat center;
	cursor: pointer;
}
#event-menu .content .waypoint:hover
{
	background: url(images/waypoint-hover.png) no-repeat center;
}
#event-menu-filler
{
	position: absolute;
	width: 117px;
	z-index: 0;
	background-color: #000;
	display: none;
	left: 5px;
}
#sound-icon
{
	position: absolute;
	left: 5px;
	width: 21px;
	height: 20px;
	background: url(images/sound-icon.png) no-repeat;
	cursor: pointer;
}
#sound-icon.mute
{
	background: url(images/sound-mute-icon.png) no-repeat;
}
#sound-icon.daily
{
	background: url(images/sound-daily-icon.png) no-repeat;
}
#sound-icon.disabled
{
	display: none;
}

#vibrate
{
	display: none;
	position: absolute;
	top: 0px;
	left: 0px;
	z-index: 0;
	width: 100%;
	height: 100%;
	overflow: hidden;
	filter: alpha(opacity=40);
	opacity: 0.4;
}
#vibrate div
{
	position: absolute;
	top: 0px;
	left: 0px;
	width: 100%;
	height: 100%;
}
#vibrate img
{
	position: absolute;
	width: 137px;
	height: 54px;
	left: -5px;
	top: -2px;
}
#settings-icon
{
	width: 20px;
	height: 20px;
	position: absolute;
	top: 0px;
	left: 128px;
	cursor: pointer;
	opacity: 0.8;
}
#settings-icon img
{
	width: 20px;
	height: 20px;
	border: 0px;
	opacity: 0.5;
}
#settings-icon img:hover
{
	opacity: 1;
}
</style>

<script type="text/javascript" language="javascript">

var eventTimers = [];
var maximumTimers = 7;
var eventQueue = [];
var queueIndex = 0;
var queuedTimes = 0;

var timerUpdate = null;
var nextRefresh = 0;
var eventMenu = null;
var icons = null;
var currentDaily = null;

var nextDaily =
{
	timer: null,
	time: null
};

var timerScroll = null;
var scrollChange = 3;

var allowDuplicates = true;
var compactView = false;
var compactTimers = 3;
var timelineStyle = 0;
var timelineOrder = 0;
var timerFormatStyle = 0;

var TimerFormatStyle =
{
	HMS: 0,
	HHMMSS: 1,
	Clock12: 2,
	Clock24: 3
}

var enableTracking = false;
var trackingPort = 18953;

var trackingData = null;
var nextTrackingUpdate = 0;

var vibrateElement = null;

var soundPlayer =
{
	ignoreCompleted: true,
	timeDelay: 0,
	state: 0, //0: default, 1: muted until daily, 2: muted
	enabled: false,
	
	playlist: 
	{
		items: [], //{path:"", volumne:1}
		randomize: false,
		position: 0,
		
		next: function()
		{
			var index = this.items.length;
			if (index > 0)
			{
				if (this.randomize)
					index = Math.floor(Math.random() * index);
				else
					index = (this.position == null ? 0 : this.position + 1) % index;
				
				this.position = index;

				return this.items[index];
			}
			
		}
	},
	
	isMuted: function()
	{
		return this.state == 2;
	}
}

var bodyHeight = 0;

var event_type =
{
	0: "low level",
	1: "standard",
	2: "hard"
}

//var System = { Gadget: { Settings: { read: function() {return ""}, readString: function() {return ""}, write: function() {} } }}
var dateOffset = 0;

function initialize()
{
	System.Gadget.settingsUI = "Settings.html";
	System.Gadget.onSettingsClosed = SettingsClosed;
	
	icons =
	{
		1: { src: "images/elementalist.png", selected: "images/elementalist-selected.png" },
		2: { src: "images/engineer.png", selected: "images/engineer-selected.png" },
		3: { src: "images/guardian.png", selected: "images/guardian-selected.png" },
		4: { src: "images/mesmer.png", selected: "images/mesmer-selected.png" },
		5: { src: "images/necromancer.png", selected: "images/necromancer-selected.png" },
		6: { src: "images/ranger.png", selected: "images/ranger-selected.png" },
		7: { src: "images/thief.png", selected: "images/thief-selected.png" },
		8: { src: "images/warrior.png", selected: "images/warrior-selected.png" }
	};

	for (var key in event_data)
	{
		event_data[key].key = key;
	}

	var soundIcon = document.getElementById("sound-icon");
	soundIcon.transition = new Transition(soundIcon, 0, 0, 100);

	vibrateElement = document.getElementById("vibrate");
	vibrateElement.transition = new Transition(vibrateElement, 50, 0, 50);

	if (IsWebMode())
	{
		var settingsIcon = document.getElementById("settings-icon");
		settingsIcon.transition = new Transition(settingsIcon, 0, 0, 100);
		
		settingsIcon.onclick = function()
		{
			System.Gadget.Settings.show();
		}
	}

	setupMenu();
	
	loadSettings();
}

function unload()
{
	if (timerUpdate != null)
		clearTimeout(timerUpdate);
	if (timerScroll != null)
		clearTimeout(timerScroll);
}

function SettingsClosed(event)
{
	if (event.closeAction == event.Action.commit)
	{
		if (timerScroll != null)
			clearTimeout(timerScroll);
		if (timerUpdate != null)
			clearTimeout(timerUpdate);
		loadSettings();
	}
}

function translateProfessionId(professionId)
{
	switch (professionId)
	{
		case 1: //guardian
			return 3;
		case 2: //warrior
			return 8;
		case 3: //engineer
			return 2;
		case 4: //ranger
			return 6;
		case 5: //thief
			return 7;
		case 6: //elementalist
			return 1;
		case 7: //mesmer
			return 4;
		case 8: //necromancer
			return 5;
	}
	
	return null;
}

function loadSettings()
{
	if (eventMenu.visible)
		closeMenu();
	
	var d = new Date(new Date().getTime() + dateOffset);
	currentDaily = System.Gadget.Settings.read("currentDaily") || d.getUTCDate();
	
	nextDaily.time = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), currentDaily + 1)).getTime();
	if (nextDaily.timer != null)
	{
		nextDaily.timer.elements.container.removeChild(nextDaily.element);
		nextDaily.element = null;
		nextDaily.timer = null;
	}
	
	timerFormatStyle = System.Gadget.Settings.read("timer-style");
	if (timerFormatStyle === "" || !(timerFormatStyle >= 0))
		timerFormatStyle = TimerFormatStyle.HMS;
		
	enableTracking = System.Gadget.Settings.read("coordinate-tracking") == true;
	trackingPort = System.Gadget.Settings.read("coordinate-tracking-port");
	if (!(trackingPort > 0))
		trackingPort = 18953;
	
	timelineOrder = System.Gadget.Settings.read("timeline-order");
	timelineOrder = timelineOrder == 1 ? 1 : 0;
	
	timelineStyle = System.Gadget.Settings.read("timeline-style");
	timelineStyle = timelineStyle == 1 ? 1 : 0;
	allowDuplicates = timelineStyle == 0;
	
	compactTimers = System.Gadget.Settings.read("compact-timers");
	if (compactTimers === "" || !(compactTimers >= 0))
		compactTimers = 3;
	
	var timers = System.Gadget.Settings.read("timer-count");
	if (!(timers > 0))
		timers = 7;
	
	loadPlaylist();
	
	setupEventQueue();
	
	maximumTimers = Math.min(Math.min(queuedTimes, timers), 99);
	compactView = compactTimers < maximumTimers;
	
	var count = maximumTimers;
	var height = compactView ? 
		51 * Math.min(compactTimers, count) + 31 * Math.max(0, count - compactTimers) - 1
		: 51 * count - 1;
	
	bodyHeight = height;
	
	document.getElementById("container").style.height = height + "px";
	
	var background = document.getElementById("background");
	if (true || compactView) //always showing lines between now
	{
		background.style.height = height + "px";
		background.style.display = "block";
	}
	else
		background.style.display = "none";
	
	var menuFiller = document.getElementById("event-menu-filler");
	var fillerHeight = 301 - height;
	menuFiller.enabled = (fillerHeight > 0);
	
	if (fillerHeight > 0)
	{
		menuFiller.style.top = height + "px";
		menuFiller.style.height = fillerHeight + "px";
		if (eventMenu.visible)
			menuFiller.style.display = "block";
		
		eventMenu.container.children[0].style.height = height + "px";
		eventMenu.container.children[1].style.top = "0px"
	}
	else
	{
		menuFiller.style.display = "none";
		
		eventMenu.container.children[0].style.height = "100%";
		eventMenu.container.children[1].style.top = (height / 2 - 301 / 2) + "px";
	}
	
	eventMenu.container.className = "";
	
	document.getElementById("sound-icon").style.top = (bodyHeight - 20 - 2) + "px";
	
	document.body.style.height = Math.max(301, height) + "px";
	
	setupTimers();
	updateTimers();
	
	nextRefresh = 0;
}

function loadPlaylist()
{
	var l = System.Gadget.Settings.read("playlist");
	try
	{
		l = eval("(" + l + ")");
	}
	catch (ex)
	{
		l = null;
	}
	
	soundPlayer.playlist.items.length = 0;
	soundPlayer.playlist.position = 0;
	
	if (l)
	{
		for (var i = 0, length = l.length; i < length; i++)
		{
			soundPlayer.playlist.items.push({ path: l[i][0], volume: l[i][1] });
		}
	}
	
	var playSound = System.Gadget.Settings.read("play-sound");
	if (playSound === "" || !(playSound >= 0))
		playSound = 0;
	
	var offset = System.Gadget.Settings.read("play-sound-offset");
	if (offset === "")
		offset = 0;
		
	var soundState = System.Gadget.Settings.read("play-sound-state");
	if (soundState === "")
		soundState = 0;
		
	offset = offset * 60 * 1000;
	
	soundPlayer.enabled = (playSound != 0);
	soundPlayer.ignoreCompleted = (playSound == 2);	
	soundPlayer.timeDelay = offset;
	soundPlayer.state = soundState;
	soundPlayer.playlist.randomize = System.Gadget.Settings.read("playlist-mode") == 1;
	
	onSoundPlayerStateChanged();
}
			
function setupMenu()
{
	var container = document.getElementById("event-menu");
	var template = document.getElementById("event-template").cloneNode(true);
	template.id = "";
	
	eventMenu =
	{
		visible: false,
		selected: 
		{
			container: document.getElementById("selected-event"),
			elements:
			{				
				container: template,
				timer: template.children[0],
				title: template.children[1],
				darken: template.children[2],
				icons: template.children[3]
			},
			timer: null,
			event: null
		},
		container: container,
		content: container.children[1].children[2],
		icons: container.children[1].children[2].children[1],
		waypoint: container.children[1].children[2].children[2]
	};
	
	eventMenu.selected.container.appendChild(template);
	
	var n = 1;
	for (var i in icons)
	{
		var img = document.createElement("img");
		
		img.src = icons[i].src;
		img.key = i;
		img.selected = false;
		
		img.onclick = function()
		{
			onIconClick(this);
		}
		
		img.onmouseenter = function()
		{
			if (!this.selected)
				this.src = icons[this.key].selected
		}
		
		img.onmouseleave = function()
		{
			if (!this.selected)
				this.src = icons[this.key].src
		}
		
		if (n % 2 == 0)
		{
			img.style.marginLeft = "5px";
		}
		n++;
		
		eventMenu.icons.appendChild(img);
	}
	
	eventMenu.container.children[0].onclick = function()
	{
		closeMenu();
	};
	
	eventMenu.container.transition = new Transition(eventMenu.container, 100);
}

function setupTimers()
{
	var container = document.getElementById("container");
	for (var i = 0, length = eventTimers.length; i < length; i++)
	{
		var o = eventTimers.pop();
		container.removeChild(o.elements.container);
	}
	for (var i = eventTimers.length; i < maximumTimers + 1; i++)
	{
		eventTimers.push(addTimer())
	}
}

function addTimer()
{
	var container = document.getElementById("container");
	var template = document.getElementById("event-template").cloneNode(true);
	
	var y = 0;
	var index = eventTimers.length;
	
	if (compactView)
	{
		if (timelineOrder == 1)
			y = bodyHeight - 50 * Math.min(index + 1, compactTimers) - 30 * Math.max(index + 1 - compactTimers, 0) - index;
		else
			y = Math.min(index, compactTimers) * 50 + Math.max(index - compactTimers, 0) * 30 + index;
	}
	else if (timelineOrder == 1)
		y = bodyHeight - 50 * (index + 1) - index;
	else
		y = 51 * index;
	
	var height = compactView ? (index >= compactTimers ? 30 : 50) : 50;
	
	template.id = "";
	template.style.height = height + "px";
	template.style.position = "absolute";
	template.style.left = "0px";
	template.style.top = y + "px";
	template.style.display = "none";
	
	var o =
	{
		index: eventTimers.length,
		key: null,
		elements:
		{
			container: template,
			timer: template.children[0],
			title: template.children[1],
			darken: template.children[2],
			icons: template.children[3],
			close: template.children[4]
		},
		y: y,
		height: height
	};
	
	template.onmouseenter = function()
	{
		onEventMouseOver(o);
	};
	
	template.onmouseleave = function()
	{
		onEventMouseOut(o);
	}
	
	template.oncontextmenu = function()
	{
		//return false;
	}
	
	template.onclick = function(event)
	{
		onEventClick(event, o);
	}
	
	o.elements.close.onclick = function(event)
	{
		event = event || window.event;
		event.cancelBubble = true;
		onEventCloseClick(event, o);
	}
	
	if (compactView && index >= compactTimers)
		o.elements.container.className = "timer compact";
			
	o.elements.timer.style.filter = "progid:DXImageTransform.Microsoft.Glow(color=000000,strength=1)";
	o.elements.title.style.filter = "alpha(opacity=70), progid:DXImageTransform.Microsoft.Glow(color=000000,strength=3)";
	o.elements.title.style.opacity = "0.7";
	
	o.elements.title.innerHTML = "";
	o.elements.title.transition = new Transition(o.elements.title, 0, 0, 70);
	o.elements.close.transition = new Transition(o.elements.close, 0, 0, 100);
	
	container.appendChild(template);
	
	return o;
}

function setupEventQueue()
{
	eventQueue.length = 0;
	
	var date = new Date(new Date().getTime() + dateOffset);
	var minutes = date.getUTCHours() * 60 + date.getUTCMinutes();
	
	for (var key in event_data)
	{
		if (!isEventEnabled(key))
			continue;
		
		var min = null; 
		
		var e = event_data[key];
		for (var i = 0, length = e.times.length; i < length; i++)
		{
			var time = e.times[i];
			var minutesSince = minutes < time ? minutes + 24 * 60 - time : minutes - time;
			var minutesUntil = 24 * 60 - minutesSince;
			var t;
			
			if (minutesSince < getExpiryMinutes(e.type))
				t = date.getTime() - (minutesSince * 60 + date.getUTCSeconds()) * 1000 - date.getUTCMilliseconds();
			else
			 	t = date.getTime() + (minutesUntil * 60 - date.getUTCSeconds()) * 1000 - date.getUTCMilliseconds();
			
			var q =
			{
				index: i,
				time: time,
				start: t,
				expires: calcExpires(t, e),
				data: e
			}
			
			if (allowDuplicates)
			{
				eventQueue.push(q);
			}
			else if (minutesSince < getExpiryMinutes(e.type))
			{
				min = q;
				break;
			}
			else if (!min || q.expires < min.expires)
			{
				min = q;
			}
		}
		
		if (!allowDuplicates && min)
			eventQueue.push(min);
	}
	
	eventQueue.sort(
		function(a, b)
		{
			return a.expires - b.expires;
		}
	);
	
	queueIndex = 0;
	queuedTimes = eventQueue.length;
}

function getExpiryMinutes(type)
{
	if (type == 1)
		return 15;
	else if (type == 2)
		return 20;
	return 10;
}

function calcExpires(start, data)
{
	var minutes = getExpiryMinutes(data.type);
	return start + (minutes * 60 - 1) * 1000
}

function scrollTimers(y, change)
{
	y = y || 0;
	
	var yLimit = compactView ? 31 : 51;
	
	if (y == 0)
	{
		var i = eventTimers.length - 1;
		updateTimer(eventTimers[i], eventQueue[(i + queueIndex) % queuedTimes]);
	}
	
	if (typeof(change) != "number")
		change = Math.min(scrollChange, yLimit - y);
	else if (y + change > yLimit)
		change = yLimit - y;
	
	for (var i = 0, length = eventTimers.length; i < length; i++)
	{
		var timer = eventTimers[i];
		
		if (timelineOrder == 1)
			timer.y += change;
		else
			timer.y -= change;
		
		if (compactView)
		{
			if (i < compactTimers)
			{
				var h = 20 * (y + change) / yLimit;
				if (timelineOrder == 1)
					timer.elements.container.style.top = (timer.y + h) + "px";
				else
					timer.elements.container.style.top = (timer.y - h) + "px";
			}
			else if (i == compactTimers)
			{
				var h = 20 * (y + change) / yLimit;
				timer.elements.container.style.height = (timer.height + h) + "px";
				if (timelineOrder == 1)
					timer.elements.container.style.top = (timer.y) + "px";
				else
					timer.elements.container.style.top = (timer.y - h) + "px";
			}
			else
				timer.elements.container.style.top = timer.y + "px";
		}
		else
			timer.elements.container.style.top = timer.y + "px";
	}
	
	if (y < yLimit)
	{
		timerScroll = setTimeout(function()
			{
				scrollTimers(y + change, scrollChange);
			}, 25);
	}
	else
	{
		if (compactView)
		{
			for (var i = 1, length = compactTimers + 1; i < length; i++)
			{
				if (timelineOrder == 1)
					eventTimers[i].y = bodyHeight - i * 50 - (i - 1);
				else
					eventTimers[i].y = (i - 1) * 50 + (i - 1);
			}
			
			if (compactTimers > 0)
			{
				eventTimers[compactTimers].height = 50;
				eventTimers[compactTimers].elements.container.className = "timer";
			}
		}
		
		var timer = eventTimers.shift(), 
		    next = eventTimers[eventTimers.length - 1];
		eventTimers.push(timer);
		
		if (timelineOrder == 1)
			timer.y = next.y - next.height - 1;
		else
			timer.y = next.y + next.height + 1;
		
		timer.elements.container.style.top = timer.y + "px";
		
		if (compactView)
		{
			timer.height = next.height;
			timer.elements.container.style.height = "30px";
			timer.elements.container.className = "timer compact";
		}
		
		var date = new Date(new Date().getTime() + dateOffset);
		var minutes = date.getUTCHours() * 60 + date.getUTCMinutes();
		var time = timer.timing.time;
		var minutesSince = minutes < time ? minutes + 24 * 60 - time : minutes - time;
		var minutesUntil = 24 * 60 - minutesSince;
		var t = date.getTime() + (minutesUntil * 60 - date.getUTCSeconds()) * 1000 - date.getUTCMilliseconds();
		
		timer.timing.start = t;
		timer.timing.expires = calcExpires(t, timer.timing.data);
		timer.timing.handled = false;
		
		timer.elements.container.style.display = "none";
		
		if (eventMenu.selected.source == timer.timing) //if the menu is showing this event, show the next available time for its timer
		{
			for (var i = 0; i < queuedTimes; i++)
			{
				var index = (queueIndex + i + 1) % queuedTimes;
				if (eventQueue[index].data == eventMenu.selected.source.data)
				{
					eventMenu.selected.source = eventQueue[index];
					break;
				}
			}
		}		
		
		queueIndex = (queueIndex + 1) % queuedTimes;
		
		if (date.getTime() > eventQueue[queueIndex].expires) //check the next one
		{
			scrollTimers(0, scrollChange - change);
		}
		else
		{
			nextRefresh = eventQueue[queueIndex].expires;
			timerScroll = null;
		}
	}
}

function requestTrackingData()
{
	nextTrackingUpdate = new Date().getTime() + 30000;
					
	ajaxRequest("GET", "http://127.0.0.1:" + trackingPort + "/",
		function(t)
		{
			try
			{
				if (t.responseText)
				{
					var data = eval("("+t.responseText+")");
					if (data.map_id > 0)
					{
						onTrackingDataReceived(data)
					}
				}
			}
			catch (ex)
			{ 
			}
		});
}

function isWithinBoundary(position, boundary)
{
	if (boundary instanceof Array)
	{
		for (var i = 0, length = boundary.length; i < length; i++)
		{
			if (isWithinBoundary(position, boundary[i]))
				return true;
		}
	}
	else if (position.x >= boundary.left && position.x <= boundary.right && 
		position.y <= boundary.top && position.y >= boundary.bottom)
	{
		return true;
	}
	
	return false;
}

function onTrackingDataReceived(data)
{
	var time = new Date().getTime();
	var waitingCount = 0;
	
	if (trackingData && trackingData.data.map_id != data.map_id)
	{
		onMapChange(trackingData.data.map_id, data.map_id);
	}
	
	trackingData = { time: time, data: data }
	
	for (var i = 0, length = maximumTimers; i < length; i++)
	{
		var timer = eventTimers[i];
		var q = eventQueue[(i + queueIndex) % queuedTimes];
		
		if (time > q.start && q.data.boundary)
		{
			waitingCount++;
			
			if (timer.tracking && timer.tracking.profession[data.identity.profession])
			{
				//event was already flagged
				
				//Allow for a 5 minute grace period to switch characters and still keep tracking enabled
				//for this event.
				//if (time - q.start > 300000)
				//	waitingCount--;
				
				if (!timer.tracking.extended && time < q.expires && q.expires - time < 60000
					&& isWithinBoundary(data, q.data.boundary))
				{
					//the player is still within the event's boundary
					//assume it's still going, extended the timer by 5 minutes.
					timer.tracking.extended = true;
					timer.timing.expires += 5 * 60 * 1000;
				}
			}
			else if (q.data.map_id == data.map_id)
			{
				if (isWithinBoundary(data, q.data.boundary))
				{
					//waitingCount--;
					timer.tracking = timer.tracking || { profession: [] };
					timer.tracking.profession[data.identity.profession] = true;
					var iconId = translateProfessionId(data.identity.profession);
					if (iconId != null)
					{
						System.Gadget.Settings.write("event-" + q.data.key + "-i" + iconId, true);
						refreshEventIcons(q.data);
					}
				}
				
				if ((!timer.tracking || !timer.tracking.extended) && time < q.expires && q.expires - time < 60000)
				{
					//player is on the map, the event is active, but the player has not entered the event's area
					//increase the event's timer by 5 minutes to give a little extra time.
					timer.tracking = timer.tracking || { profession: [] };
					timer.tracking.extended = true;
					timer.timing.expires += 5 * 60 * 1000;
				}
			}
		}
		else
		{
			if (waitingCount == 0)
			{
				nextTrackingUpdate = q.start;
				return;
			}
			break;
		}
	}
	
	nextTrackingUpdate = time + (waitingCount > 0 ? 10000 : 30000);
}

function updateTimers()
{
	var date = new Date(new Date().getTime() + dateOffset);
	var d = date.getTime();
	
	if (d > nextRefresh && timerScroll == null)
	{
		if (d > eventQueue[queueIndex].expires)
		{			
			if (allowDuplicates)
			{
				nextRefresh = d + 60000;
				scrollTimers();
			}
			else
			{
				var minutes = date.getUTCHours() * 60 + date.getUTCMinutes();
				while (d > eventQueue[queueIndex].expires)
				{
					var q = eventQueue[queueIndex];
					q.index = (q.index + 1) % q.data.times.length;
					
					var time = q.data.times[q.index];
					var minutesSince = minutes < time ? minutes + 24 * 60 - time : minutes - time;
					var minutesUntil = 24 * 60 - minutesSince;
					var t = d + (minutesUntil * 60 - date.getUTCSeconds()) * 1000 - date.getUTCMilliseconds();
					
					q.start = t;
					q.expires = calcExpires(t, q.data);
					q.handled = false;
					
					queueIndex = (queueIndex + 1) % queuedTimes;
				}
	
				eventQueue.sort(
					function(a, b)
					{
						return a.expires - b.expires;
					}
				);
				
				queueIndex = 0;
				
				nextRefresh = eventQueue[queueIndex].expires;
			}
		}
		else
			nextRefresh = eventQueue[queueIndex].expires;
	}
	
	for (var i = 0, length = maximumTimers + 1; i < length; i++)
	{
		var index = (i + queueIndex) % queuedTimes;
		
		if (i < length - 1 || timerScroll)
			updateTimer(eventTimers[i], eventQueue[index]);
	}
	
	if (eventMenu.selected.source)
	{
		updateTimer(eventMenu.selected, eventMenu.selected.source);
	}
	
	if (enableTracking && d > nextTrackingUpdate)
	{
		requestTrackingData();
	}
	
	if (date.getUTCDate() != currentDaily)
	{
		currentDaily = date.getUTCDate();
		System.Gadget.Settings.write("currentDaily", currentDaily);
		
		nextDaily.time = new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), currentDaily + 1)).getTime();
		if (nextDaily.timer != null)
		{
			nextDaily.timer.elements.container.removeChild(nextDaily.element);
			nextDaily.element = null;
			nextDaily.timer = null;
		}
		
		if (soundPlayer.state == 1)
		{
			soundPlayer.state = 0;
			onSoundPlayerStateChanged();
		}
		
		for (var k in event_data)
		{
			for (var i in icons)
			{
				System.Gadget.Settings.write("event-" + k + "-i" + i, "");
			}
		}
		
		for (var i in eventTimers)
		{
			var e = eventTimers[i];
			e.elements.icons.innerHTML = "";
		}
		
		if (eventMenu.visible)
			openMenu(eventMenu.selected.source);
	}
	
	timerUpdate = setTimeout(function()
		{
			updateTimers();
		}, 1000);
}

function updateTimer(timer, q)
{
	var date = new Date(new Date().getTime() + dateOffset);
	
	if (timer.data != q.data)
	{
		timer.data = q.data;
		
		timer.elements.title.innerHTML = q.data.name;
	
		if (q.data.image)
			timer.elements.container.style.backgroundImage = "url('" + q.data.image + "')";
			
		loadEventIcons(timer, q.data)
	}
	
	if (timer.timing != q)
	{
		timer.timing = q;
		
		if (enableTracking)
			delete timer.tracking;
		
		//show the daily on the event closest to reset, which may change over time, if only showing unique events
		//note that when showing only unique, timers don't move, so the daily will have to move instead
		if (timer != eventMenu.selected && q.start >= nextDaily.time && (nextDaily.timer == null || 
			q.start < nextDaily.timing.start || q === nextDaily.timing))
		{
			if (nextDaily.timer != null)
				nextDaily.timer.elements.container.removeChild(nextDaily.element);
			
			nextDaily.timer = timer;
			nextDaily.timing = q;
			
			var div = document.createElement("div");
			div.className = "daily-reset";
			div.title = "Daily Reset"
			
			nextDaily.element = div;
			timer.elements.container.appendChild(div);
		}
	}
	
	var time = date.getTime();
	var remaining, darken, className;
	
	if (time > q.start)
	{
		remaining = Math.floor((q.start - time) / 1000);
		if (timer.tracking && timer.tracking.extended)
			className = "extended"
		else
			className = "active";
		darken = 5;
	}
	else
	{
		remaining = Math.floor((q.start - time) / 1000);
		if (remaining < 10 * 60)
		{
			className = "preevent";
			darken = 15;
		}
		else if (remaining < 20 * 60)
		{
			className = "window";
			darken = 30;
		}
		else
		{
			className = "inactive";
			darken = 50;
		}
	}
	
	var value = null;
	
	switch (timerFormatStyle)
	{
		case TimerFormatStyle.Clock12:
		case TimerFormatStyle.Clock24:
			value = formatTimestamp(q.start);
			break;
		default:
			value = formatTimer(remaining);
	}
	
	if (timer.elements.timer.innerHTML != value)
		timer.elements.timer.innerHTML = value;
	
	if (timer.elements.timer.className != className)
		timer.elements.timer.className = className;
	
	if (timer.elements.darken.opacity != darken)
	{
		timer.elements.darken.opacity = darken;
		timer.elements.darken.style.filter = "alpha(opacity="+darken+")";
		timer.elements.darken.style.opacity = darken / 100;
	}
	
	if (timer.elements.container.style.display != "block")
		timer.elements.container.style.display = "block";
	
	if (soundPlayer.enabled && !timer.timing.handled)
	{
		if (time >= q.start + soundPlayer.timeDelay - 1000)
		{
			timer.timing.handled = true;
			var difference = Math.abs(q.start + soundPlayer.timeDelay - time);
			if (difference < 10000) //account for a little lag, but ignore timers already past
			{
				if (!soundPlayer.isMuted())
				{
					if (soundPlayer.state != 1 && (!soundPlayer.ignoreCompleted || !hasEventBeenCompleted(q.data))
						|| (q.start + 60000) > nextDaily.time) //account for daily reset
					{
						var sound = soundPlayer.playlist.next();
						if (sound)
							playSound(sound);
					}
				}
				
				vibrateTimer(timer);
			}
		}
	}
}

function vibrateTimer(timer)
{
	vibrate(timer, 30, function(v, ticks)
		{
			if (ticks == 12)
			{
				v.element.transition.fadeOut(500, "none", function()
				{
					v.stop();
				});
			}
		});
}

function vibrate(timer, maxTicks, onTickCallback)
{
	var timeout = null;
	var vibrate = vibrateElement;
	var container = vibrate.childNodes[0];
	var img = container.childNodes[0];
	var label = container.childNodes[1];
	
	var r = 
	{
		stop: function() 
		{ 
			if (timeout)
				clearTimeout(timeout);
			timeout = false;
			this.element.style.display = "none";
			this.element.vibrate = null;
		},
		element: vibrate
	}
	
	if (vibrate.parentNode)
		vibrate.parentNode.removeChild(vibrate);
	
	if (vibrate.vibrate)
		vibrate.vibrate.stop();
	vibrate.vibrate = r;
		
	vibrate.transition.fadeIn(100, "block");
	
	var height = timer.elements.container.offsetHeight;
	if (height != 0 && height != 50)
		img.style.top = ((height - 50) / 2) + "px";
	else
		img.style.top = null;
	
	img.src = timer.data.image;
	vibrate.style.display = "block";
	
	timer.elements.container.appendChild(vibrate);
	
	function _vibrate(container, tick, intensity)
	{
		if (label.className != timer.elements.timer.className)
			label.className = timer.elements.timer.className;
		if (label.innerHTML != timer.elements.timer.innerHTML)
			label.innerHTML = timer.elements.timer.innerHTML;
		
		switch(tick % 4)
		{
			case 0:
				container.style.left = (-5 * intensity) + "px";
				container.style.top = "0px";
				break;
			case 1:
				container.style.left = (5 * intensity) + "px";
				container.style.top = "0px";
				break;
			case 2:
				container.style.left = "0px";
				container.style.top = (-2 * intensity) + "px";
				break;
			case 3:
				container.style.left = "0px";
				container.style.top = (2 * intensity) + "px";
				break;
		}
		
		if (timeout !== false && (!onTickCallback || onTickCallback(r, tick) !== false))
		{
			timeout = setTimeout(function()
				{
					if (tick < maxTicks)
						_vibrate(container, tick + 1, intensity);
					else
						container.parentNode.style.display = "none";
				}, 100);
		}
	}
	
	_vibrate(container, 0, 1);
	
	return  r;
}

function formatTimestamp(t)
{
	var d = new Date(t);
	var h = d.getHours();
	var m = d.getMinutes();
	m = (m < 10 ? "0" + m : m);
	
	switch (timerFormatStyle)
	{
		case TimerFormatStyle.Clock12:
			if (h >= 12)
				return (h == 12 ? 12 : h - 12) + ":" + m + " PM";
			else
				return (h == 0 ? 12 : h) + ":" + m + " AM";
		case TimerFormatStyle.Clock24:
			return (h < 10 ? "0" + h : h) + ":" + m;
	}
}

function formatTimer(seconds)
{
	var s = Math.abs(seconds); //seconds negative when showing elapsed time
	
	if (s >= 3600)
	{
		var h = Math.floor(s / 3600);
		var m = Math.floor((s % 3600) / 60);
		var s = s % 60;
		
		switch (timerFormatStyle)
		{
			case TimerFormatStyle.HHMMSS:
				return h + ":" + (m < 10 ? "0" + m : m) + ":" + (s < 10 ? "0" + s : s);
			default:
				return h + "<span>h</span> " + m + "<span>m</span>";
		}
	}
	else if (s >= 60)
	{
		var m = Math.floor(s / 60);
		s = s % 60;
		
		switch (timerFormatStyle)
		{
			case TimerFormatStyle.HHMMSS:
				return m + ":" + (s < 10 ? "0" + s : s);
			default:
				if (m >= 10 && seconds > 0)
					return m + "<span>m</span>";				
				return m + "<span>m</span> " + s + "<span>s</span>";
		}
	}
	else
	{
		switch (timerFormatStyle)
		{
			case TimerFormatStyle.HHMMSS:
				return "0:" + (s < 10 ? "0" + s : s);
			default:
				return s + "<span>s</span>";
		}
	}
}

function playSound(sound)
{
	System.Sound.playSound(sound.path);
}

function hasEventBeenCompleted(data)
{
	for (var id in icons)
	{
		if (System.Gadget.Settings.read("event-" + data.key + "-i" + id) == true)
			return true;
	}
	
	return false;
}

function onMouseOver()
{
	if (!eventMenu.visible)
	{
		if (soundPlayer.enabled)
		{
			var soundIcon = document.getElementById("sound-icon");
			soundIcon.transition.fadeIn(100, "block");
		}
	}
	
	if (IsWebMode())
	{
		document.getElementById("settings-icon").transition.fadeIn(100, "block");
	}
}

function onMouseOut()
{
	if (!eventMenu.visible)
	{
		if (soundPlayer.enabled)
		{
			var soundIcon = document.getElementById("sound-icon");
			soundIcon.transition.fadeOut(100, "none");
		}
	}
	
	if (IsWebMode())
	{
		document.getElementById("settings-icon").transition.fadeOut(100, "none");
	}
}

function onEventMouseOver(timer)
{
	timer.elements.title.transition.fadeIn(100, "block");
	
	var time = new Date(new Date().getTime() + dateOffset).getTime();
	if (timer.timing && time > timer.timing.start && timer === eventTimers[0])
		timer.elements.close.transition.fadeIn(70, "block");
	else if (timer.elements.close.style.display != "none")
		timer.elements.close.style.display = "none";
}

function onEventMouseOut(timer)
{
	timer.elements.title.transition.fadeOut(500, "none");
	
	var time = new Date(new Date().getTime() + dateOffset).getTime();
	if (timer.elements.close.style.display != "none")
		timer.elements.close.transition.fadeOut(500, "none");
}

function onEventClick(e, timer)
{
	openMenu(timer.timing, timer)
}

function onEventCloseClick(e, timer)
{
	var time = new Date(new Date().getTime() + dateOffset).getTime();
	if (time > timer.timing.start && time < timer.timing.expires)
	{
		clearTimeout(timerUpdate);
		timer.timing.expires = 0;
		nextRefresh = 0;
		updateTimers();
	}
}

function setWaypointFlyout(data)
{
	var flyout = System.Gadget.Flyout;
	if (flyout.window)
		flyout.window.loadMap(data.map);
	else
		flyout.document.parentWindow.loadMap(data.map);
}

function openMenu(q, timer)
{
	if (eventMenu.visible)
		closeMenu();

	if (!eventMenu.visible)
	{
		if (timer)
			moveMenu(timer);
		
		eventMenu.visible = true;
		
		eventMenu.container.transition.fadeIn(100, "block");
		
		var menuFiller = document.getElementById("event-menu-filler");
		if (menuFiller.enabled)
			menuFiller.style.display = "block";
	}
	
	eventMenu.waypoint.style.display = q.data.map ? "block" : "none";
	
	eventMenu.waypoint.onclick = function()
	{
		if (!System.Gadget.Flyout.show)
		{
			System.Gadget.Flyout.file = "Waypoint.html";
			
			System.Gadget.Flyout.onShow = function()
			{
				setWaypointFlyout(q.data);
			}
			
			if (System.Gadget.Flyout.setVisibility)
				System.Gadget.Flyout.setVisibility(true);
			else
				System.Gadget.Flyout.show = true;
		}
		else
		{
			if (System.Gadget.Flyout.setVisibility)
				System.Gadget.Flyout.setVisibility(false);
			else
				System.Gadget.Flyout.show = false;
		}
	};
	
	eventMenu.selected.source = q;
	
	for (var i = 0; i < eventMenu.icons.children.length; i++)
	{
		var icon = eventMenu.icons.children[i];
		var v = System.Gadget.Settings.read("event-" + q.data.key + "-i" + icon.key);
		var src = (v == true) ? icons[icon.key].selected : icons[icon.key].src;
		icon.src = src;
		icon.selected = (v == true);
	}
	
	loadEventIcons(eventMenu.selected, eventMenu.selected.source.data);
	updateTimer(eventMenu.selected, eventMenu.selected.source);
}

function moveMenu(timer)
{
	var menuHeight = 301;
	
	if (bodyHeight <= menuHeight + 100)
		return;
	
	var className = "";
	
	var y = Math.max(0, timer.y + (timer.height / 2 - 25));
	if (y + menuHeight > bodyHeight)
	{
		y = Math.min(bodyHeight - menuHeight, y - menuHeight + 50);
		if (y > 0)
			className = "bottom";
		else
			y = bodyHeight - menuHeight;
	}
	
	if (eventMenu.container.className != className)
		eventMenu.container.className = className;
	
	eventMenu.container.children[1].style.top = y + "px";		
}

function closeMenu()
{
	if (!eventMenu.visible)
		return;
	
	eventMenu.visible = false;
	
	eventMenu.container.transition.fadeOut(100, "none", function()
	{
		var menuFiller = document.getElementById("event-menu-filler");
		if (menuFiller.enabled)
			menuFiller.style.display = "none";
	});
	
	refreshEventIcons(eventMenu.selected.source.data);
	
	eventMenu.selected.source = null;
	
	if (System.Gadget.Flyout.show)
		System.Gadget.Flyout.show = false;
}

function onIconClick(img)
{
	var selected = (img.selected = !img.selected);
	img.src = selected ? icons[img.key].selected : icons[img.key].src;
	
	System.Gadget.Settings.write("event-" + eventMenu.selected.source.data.key + "-i" + img.key, selected);
	
	loadEventIcons(eventMenu.selected, eventMenu.selected.source.data);
	
	if (selected)
		closeMenu();
}

function isEventEnabled(key)
{
	var v = System.Gadget.Settings.read("event-" + key);	
	return v !== false;
}

function loadEventIcons(timer, data)
{
	timer.elements.icons.innerHTML = "";
	
	for (var i in icons)
	{
		var v = System.Gadget.Settings.read("event-" + data.key + "-i" + i);
		if (v == true)
		{
			var img = document.createElement("img");
			img.src = icons[i].src;				
			
			timer.elements.icons.appendChild(img);
		}
	}
}

//loads icons for the specified event
function refreshEventIcons(data)
{
	for (var i = 0, length = eventTimers.length; i < length; i++)
	{
		if (eventTimers[i].data == data)
		{
			loadEventIcons(eventTimers[i], data || eventTimers[i].data);
			if (!allowDuplicates)
				break;
		}
		else if (!data)
			loadEventIcons(eventTimers[i], eventTimers[i].data);
	}
}

function onSoundPlayerStateChanged()
{
	var icon = document.getElementById("sound-icon");
	
	if (!soundPlayer.enabled)
		icon.className = "disabled";
	else if (soundPlayer.state == 2)
		icon.className = "mute";
	else if (soundPlayer.state == 1)
		icon.className = "daily";
	else
		icon.className = "";
	
	System.Gadget.Settings.write("play-sound-state", soundPlayer.state)
}

function onMapChange(previous, current)
{
	var time = new Date().getTime();
	
	for (var i = 0, length = eventTimers.length; i < length; i++)
	{
		var timer = eventTimers[i];
		
		if (time > timer.timing.start)
		{
			if (timer.tracking)
			{
				if (timer.data.map_id == previous)
				{
					//event was flagged as completed and the zone has changed
					//the event was probably completed
					//shorten the expiry to 60 seconds
					var expiry = time + 60000;
					
					if (expiry < timer.timing.expires)
					{
						timer.tracking.extended = true;
						timer.tracking.expires = timer.timing.expires;
						
						timer.timing.expires = expiry;
						nextRefresh = expiry;
					}
				}
				else if (timer.data.map_id == current)
				{
					if (timer.tracking.expires > timer.timing.expires)
					{
						//event expiry was reduced, but the player returned to the zone
						//assuming the player returned to the event
						
						timer.tracking.extended = false;
						timer.timing.expires = timer.tracking.expires;
						delete timer.tracking.expires;
					}
				}
			}
		}
		else
			break;
	}
}
function onSoundClick()
{
	soundPlayer.state = (soundPlayer.state + 1) % 3;
	onSoundPlayerStateChanged();
}

function pulse(e, pulseCount, minAlpha, maxAlpha, initialAlpha, alphaChange, onCompleteCallback)
{
	var timer = null;
	
	function setAlpha(e, alpha)
	{
		e.style.filter = "alpha(opacity=" + alpha + ")";
	}
	
	function _pulse(e, count, min, max, alpha, d, initial)
	{
		alpha += d;
		
		if (d > 0 && alpha > max || d < 0 && alpha < min)
		{
			if (--count == 0)
			{
				timer = null;
				if (onCompleteCallback)
					onCompleteCallback();
				return;
			}
			return _pulse(e, count, min, max, alpha, -d, initial);
		}
		
		setAlpha(e, alpha);
			
		timer = setTimeout(
			function()
			{
				_pulse(e, count, min, max, alpha, d, initial);
			}, 25);
	}
	
	_pulse(e, pulseCount, minAlpha, maxAlpha, initialAlpha, alphaChange, alphaChange);
	
	return {
		stop: function()
		{
			if (timer != null)
				clearTimeout(timer);
		}
	};
}
</script>

</head>
<body onLoad="initialize()" onUnload="unload()" onmouseenter="onMouseOver()" onmouseleave="onMouseOut()">

<g:background>

<div id="background" style="width: 100%; position: absolute; top: 0px; left: 0px; background-color: #000; z-index: 0;"></div>

<div id="title"></div>

<div id="event-template" class="timer">
    <span type="timer">--:--</span>
    <span type="title"></span>
    <div class="darken"></div>
    <span type="icons"></span>
    <div class="close"></div>
</div>

<div id="container">
</div>
        
<div id="event-menu">
	<div class="background"></div>
    <div class="container">
        <div id="selected-event"></div>
        <div class="arrow"></div>
        <div class="content">
            <div class="close" onclick="closeMenu()"></div>
            
            <div class="icons"></div>
            <div class="waypoint"></div>
            
            <div class="background"></div>
        </div>
    </div>
</div>
<div id="event-menu-filler"></div>

<div id="sound-icon" onClick="onSoundClick()"></div>

<div id="vibrate"><div><img /><span type="timer"></span></div></div>

<div id="settings-icon"><img src="images/gear.png" /></div>

</g:background>

</body>
</html>